<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <title>Beware! Floating pies!</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="">
    <meta name="author" content="">
    <script type="text/javascript" src="js/vendor/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="js/jQSparql.js"></script>
    <script type="text/javascript" src="js/d3.js"></script>
    <!-- CSS -->
    <link href="css/bootstrap.css" rel="stylesheet">
    <style type="text/css">

      /* Sticky footer styles
      -------------------------------------------------- */

      html,
      body {
        height: 100%;
        /* The html and body elements cannot have any padding or margin. */
      }

      /* Wrapper for page content to push down footer */
      #wrap {
        min-height: 100%;
        height: auto !important;
        height: 100%;
      }
      
      .container {
    width:100%;
    position:absolute;              
    min-height:100%; !important /* browser fill */
    height:auto;
	  }
	  
.edetails {
padding-top: 2px;
padding-left: 5px;
margin-top: 5px;
border:2px solid;
border-radius:5px;
-moz-border-radius:5px; /* Old Firefox */
	
}


.details {
  color:black;
  font-size: 10px;
  font-weight: bold;
  background-color:rgba(255,255,255,1);
  padding: 10px;
  border-radius: 8px;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  position: relative;
 font-family: sans-serif;
}
	  
#details {
	font-size: 12px;
	margin-top: 20px;
	margin-left: 5px;
	width: 300px;
	float: right; 
	position:relative;
	right:0;
	top:0;
}

#details h1 { font-size: 20px;}

#details h2 { margin: 0; font-size: 15px;}

#details h3 { margin: 0; padding: 0; font-size: 10px;}

#details p { margin: 0; }
 
#svg { user-select: none; }

#title {
	opacity:0.4;
   -webkit-text-stroke-width: 1px;
   -webkit-text-stroke-color: white;
	position: absolute;
    top: 30%;
    left: 30%;
	z-index:1;
	-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}

.link {
  stroke: #000;
  stroke-width: 0.5px;
}

.elink {
  stroke: #000;
  stroke-width: 0.5px;
  opacity: 0;
}



.tip {
	user-select: none;
	fill: #000000;
	stroke: #000000;
	font-family: sans-serif;
	font-size: 12px;
	stroke-width: 0.2;
}

.text {
  fill: #ffffff;
  stroke: #ffffff;
  pointer-events: none;
  font-family: sans-serif;
  user-select: none;
}

.label {
  stroke: #000000;
  stroke-width: 0.2;
  pointer-events: none;
  font-family: sans-serif;
  user-select: none;
}

.node:hover .text {
   fill: #E0E0E0;
   stroke: #E0E0E0;
}

.graph {
 fill: #FC425A;   
}


path.link {
  fill: none;
  stroke: #666;
  stroke-width: 1.5px;
}

marker#licensing {
  fill: green;
}

path.link.licensing {
  stroke: green;
}

path.link.resolved {
  stroke-dasharray: 0,2 1;
}

.node {
  
  stroke: #000;
  stroke-width: 0px;
  cursor: default;
  user-select: none;
}

.endpoint {
	stroke: white;
	stroke-width: 1px;
    cursor: default;
    user-select: none;
}

.endpoint:hover + .group {
	opacity: 0.8;
}

.group {
	
	opacity: 0.1;
}

.button { display: block;}

   ul {
	list-style-type: none;
	list-style: none;
	margin-left: 1;
	text-indent: -3px;
	}
	
.namespaces {
  margin-left: 5px;;
  font-size: 10px;
  
}

  </style>
  


<script type='text/javascript'>

$(document).ready(function() {

var sparqlEndpoints = ["http://data.aalto.fi/sparql","http://data.uni-muenster.de/sparql","http://data.open.ac.uk/query","http://sparql.data.southampton.ac.uk/","http://resrev.ilrt.bris.ac.uk/data-server-workshop/sparql"];

var sparql = new jQSparql();
sparql.addPrefix("aiiso","http://purl.org/vocab/aiiso/schema#");
var prefix = sparql.prefix();

var propertyMode = false;
var loading = false;
var totalInstances = 0;
var sameInstances = 0;
var otherInstances = 0;
var sameClasses = 0;
var otherClasses = 0;

var posX;
var posY;

$("#svg").mousemove(function(event) {
  posX = event.pageX;
  posY = event.pageY;
});

var width = $("#svg").width()-320,
    height = $("#svg").height();
 
var color = ["#1f77b4", "#aec7e8",
  "#ff7f0e", "#ffbb78",
  "#2ca02c", "#98df8a",
  "#d62728", "#ff9896",
  "#9467bd", "#c5b0d5",
  "#8c564b", "#c49c94",
  "#e377c2", "#f7b6d2",
  "#7f7f7f", "#c7c7c7",
  "#bcbd22", "#dbdb8d",
  "#17becf", "#9edae5"];

var nodes = [],
    links = [],
    hNodes = [],
    hLinks = [];

 var tooltip = d3.select("#svg")
    .append("div")
    .attr("id","tooltip")
     .attr("class","details")
    .style("position", "absolute")
    .style("visibility", "hidden");

var force = d3.layout.force()
    .friction(0.5)
    .gravity(0.01)
    .charge(-6000)
    .linkDistance(250)
    .linkStrength(0.5)
    .size([width, height])
    .on("tick", tick);

var svg = d3.select("#svg").append("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("pointer-events", "all")
  .append('g')
  .attr("id","rotate")
    .call(d3.behavior.zoom().on("zoom", redraw))
  .append('g');
  

var defs = svg.append("svg:defs");
var db = defs.append("g");
db.attr("id","db");
//M69,27C120,45,132,10,134,0s-1,50-40,77 c-18,10-13,10-20,9L1,55-27z
// M69,27C120,45,132,10,134,0s-1,50-40,77 c-18,10-13,10-20,9L1,55z
// M69,27C120,45,132,10,134,0s-1,50-40,77 c-18,10-13,10-20,9L1,42.259l67.353-27.62C70.604,14.639,68.979,14.179,77.088,17.833z
db.append("path").attr("d","M69,27 C120,45,132,10,134,0 s-1,50-57,87  L1,55z");
db.append("polygon").attr("points","75,160 0,126 0,56 75,88");
db.append("polygon").attr("points","76,160 138,127 138,57 76,89");

var node, link, path, g, gr;

svg.append('rect')
    .attr('width', width*2000)
    .attr('height', height*2000)
    .attr('fill', 'white')
    .attr("x",-2000) // Ugly hack
    .attr("y",-2000);

$(document).ajaxStop(function() {
$("#load").html("");
loading = false;
});
	
$(document).ajaxStart(function() {
$("#load").html("Loading ...");
loading = true;
});

function redraw() {
  svg.attr("transform",
      "translate(" + d3.event.translate + ")"
      + " scale(" + d3.event.scale + ")")
}

var classes = [];
var properties = [];

var endpoints = ["http://data.aalto.fi/sparql","http://data.open.ac.uk/query"];
var names = ["Aalto","Open University"];
var eNodes = [];
var group;

function startGraph() {
for(i in endpoints) {
	xyrand = randXY(width/2,height/2,200)
	var e = {size: 100, id:endpoints[i],name:endpoints[i],type:"endpoint",totalCount:0,sameCount:0,sameClass:0,namespaces:[],x:xyrand.x,y:xyrand.y};
	eNodes[endpoints[i]] = e;
	nodes.push(e);
}


sparql.multiQuery(endpoints, "SELECT ?sc (count(?s) as ?c) WHERE { ?s a ?sc  FILTER(!REGEX(STR(?sc), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')) FILTER(!REGEX(STR(?sc), 'http://www.w3.org/2000/01/rdf-schema#')) FILTER(!REGEX(STR(?sc), 'http://www.w3.org/2002/07/owl#'))  } GROUP BY ?sc","sproxy.php?service-uri=").done(function(responses) {

for(r in responses) {
	console.log(responses[r].endpoint);
	console.log(responses[r].data);
	var data = responses[r].data;
	var endpoint = responses[r].endpoint;
	var eNode = eNodes[endpoint];
	
    for(i in data.results.bindings) {
	  var sameClass = $.grep($(classes), function(e){ return e.id == data.results.bindings[i].sc.value; });
	  var cCount = parseInt(data.results.bindings[i].c.value);
	  // Add to total count of instances
	  eNode.totalCount+=cCount;
	 // If new node
	  if(sameClass.length == 0) {
		  var namespace = data.results.bindings[i].sc.value.replace(/[^#|^/]+$/g,"");
		  
		  console.log(eNode);
		  var namespaces = $.grep(eNode.namespaces, function(e) { return e.namespace === namespace });
		  console.log(namespaces);
		  
		  if(namespaces.length>0) {
			  namespaces[0].usage+=1;
			  namespaces[0].instances+=cCount;
		  }
		  else eNode.namespaces.push({namespace:namespace,usage:1,instances:cCount});
		  
		  var xyrand = randXY(eNode.x,eNode.y);
		  var newClass = {namespace: namespace, size: 0, data: new Array({label:endpoint,value:cCount}), id: data.results.bindings[i].sc.value, name:sparql.prefixify(data.results.bindings[i].sc.value,sparql.lookup),type:"class",x:xyrand.x,y:xyrand.y};
		  classes.push(newClass);
	  } else {
		  // Add data to existing node
		  sameClass[0].data.push({label:endpoint,value:cCount});
		  }
	} 
}


for(e in eNodes) {
eNodes[e].namespaces.sort(function(a,b) { return b.usage - a.usage; });
}

var same = $.grep($(classes), function(e){ return e.data.length>1});
var other = $.grep($(classes), function(e){ return e.data.length==1});
sameClasses = same.length; 	
otherClasses = other.length;

for(i in other) {
hNodes.push(other[i]);
otherInstances+=parseInt(other[i].data[0].value);
var d = eNodes[other[i].data[0].label];
hLinks.push({source:d,target:other[i],id:d.id,data: new Array({label:other[i].data[0].label,value:0}),type:"endpoint"});
 }					  			  


for(i in same) {
nodes.push(same[i]);
for(x in same[i].data) {
	sameInstances+=parseInt(same[i].data[x].value);
	eNodes[same[i].data[x].label].sameCount+=parseInt(same[i].data[x].value);
	eNodes[same[i].data[x].label].sameClass+=1;
	var d = eNodes[same[i].data[x].label];
	var l = {source:d,target:same[i],id:d.id,data: new Array({label:same[i].data[x].label,value:0}),type:"endpoint"};
	//if(same[i].data.length>1) console.log(l);
	links.push(l);
}
}

totalInstances = otherInstances+sameInstances;

var newStats = [];
getStatistics(nodes,newStats);
for(i in newStats) console.log(newStats[i].namespace);


start();



});

start();




}

/*
SELECT ?p ?oc (count(?p) as ?count) WHERE { ?s a <"+d.id+"> . ?s ?p ?o . ?o a ?oc } GROUP BY ?oc ?p
*/
function getPropertyUsages(d) {

	console.log("Querying object property usage: ");
	var endpoints = [];
	for(e in d.data) {
		endpoints.push(d.data[e].label);
	}
	
// FILTER(!REGEX(STR(?p), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')) FILTER(!REGEX(STR(?p), 'http://www.w3.org/2000/01/rdf-schema#')) FILTER(!REGEX(STR(?p), 'http://www.w3.org/2002/07/owl#'))
  sparql.multiQuery(endpoints, "SELECT ?p ?oc (count(?p) as ?c) WHERE { ?s a <"+d.id+"> . ?s ?p ?o . ?o a ?oc FILTER(!REGEX(STR(?p), 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')) FILTER(!REGEX(STR(?p), 'http://www.w3.org/2000/01/rdf-schema#')) FILTER(!REGEX(STR(?p), 'http://www.w3.org/2002/07/owl#')) } GROUP BY ?p ?oc ","sproxy.php?service-uri=").done(function(responses) {
    
    for(r in responses) {
	console.log(responses[r].endpoint);
	console.log(responses[r].data);
	var data = responses[r].data;
	var endpoint = responses[r].endpoint;
	var eNode = eNodes[endpoint];
	
    if(typeof(data.results.bindings)!='undefined' && data.results.bindings.length>0 && typeof(data.results.bindings[0].p)!='undefined') {
		
	//	var endpointFound = $.grep(nodes, function(e){ return e.id == endpoint});
	 //   if(endpointFound.length==0) { console.log("pushing: "); console.log(eNodes[endpoint]); nodes.push(eNodes[endpoint]); }
	  //  else { console.log("wtf"); console.log(eNodes[endpoint]); console.log(endpointFound); }
    
    for(i in data.results.bindings) {
		
	  var p = $.grep($(links), function(e){ return e.id == (data.results.bindings[i].p.value+data.results.bindings[i].oc.value); });
	  var oc = $.grep($(nodes), function(e){ return e.id == (data.results.bindings[i].p.value+data.results.bindings[i].oc.value); });
	   
	 if(oc.length==0) {
		var namespace = data.results.bindings[i].oc.value.replace(/[^#|^/]+$/g,"");
		var xyrand = randXY(eNode.x,eNode.y);	
		oc = {namespace: namespace, size: 0, uri: data.results.bindings[i].oc.value,id: data.results.bindings[i].p.value+data.results.bindings[i].oc.value, data: new Array({label:endpoint,value:parseInt(data.results.bindings[i].c.value)}), name:sparql.prefixify(data.results.bindings[i].oc.value,sparql.lookup), type:"classUsage",x:xyrand.x,y:xyrand.y};  	  
		nodes.push(oc);
		links.push({source:eNodes[endpoint], target:oc, id:d.id, type:"endpoint"});
	 } else {
		 oc = oc[0];
		 oc.data.push({label:endpoint,value:parseInt(data.results.bindings[i].c.value)});
		 links.push({source:eNodes[endpoint], target:oc, id:d.id, type:"endpoint"});
	 }

	if(p.length == 0) {
		  var namespace = data.results.bindings[i].p.value.replace(/[^#|^/]+$/g,"");
		  p = {namespace: namespace, source: d, target: oc, data: new Array({label:endpoint}), id: data.results.bindings[i].p.value+data.results.bindings[i].oc.value, name:sparql.prefixify(data.results.bindings[i].p.value,sparql.lookup),type:"property"};
	      oc.ref=p;
	      links.push(p); }
	 else { 
		  p = p[0];
		  p.data.push({label:endpoint});
		  }
	
 }}

}


// (datatype(?o) as ?ot)
	sparql.multiQuery(endpoints, "SELECT ?p (count(?p) as ?c) WHERE { ?s a <"+d.id+"> . ?s ?p ?o FILTER isLiteral(?o) } GROUP BY ?p","sproxy.php?service-uri=").done(function(responses) {
	for(r in responses) {
	console.log(responses[r].endpoint);
	console.log(responses[r].data);
	var data = responses[r].data;
	var endpoint = responses[r].endpoint;
	var eNode = eNodes[endpoint];
	
	     if(typeof(data.results.bindings)!='undefined' && data.results.bindings.length>0 && typeof(data.results.bindings[0].p)!='undefined') {
			
	//	var endpointFound = $.grep(nodes, function(e){ return e.id == endpoint});
	  //  if(endpointFound.length==0) { console.log("pushing: "); console.log(eNodes[endpoint]); nodes.push(eNodes[endpoint]); }
	  //  else { console.log("wtf"); console.log(eNodes[endpoint]); console.log(endpointFound); }
			 
	for(i in data.results.bindings) {
		  
		  var datatype = "Literal"
		  if(data.results.bindings[i].ot != undefined) {
			  datatype = data.results.bindings[i].ot.value;
		  }
		  
		   var results = $.grep(nodes, function(e){ return e.id == (data.results.bindings[i].p.value)});
		   var p = $.grep($(links), function(e){ return e.id == (data.results.bindings[i].p.value); });
		   

		   var ot = null; 
		   
          if(results.length == 0) {
			var xyrand = randXY(eNode.x,eNode.y);
			ot = {size: 0, data: new Array({label:endpoint,value:parseInt(data.results.bindings[i].c.value)}), uri: data.results.bindings[i].p.value, id: data.results.bindings[i].p.value, name:datatype!="Literal"?sparql.prefixify(datatype):datatype,type:"literalUsage",x:xyrand.x,y:xyrand.y};
			nodes.push(ot);
			links.push({source:eNodes[endpoint], target:ot, id:d.id, type:"endpoint"});
	     } else { 
	      ot = results[0];   
	      ot.data.push({label:endpoint,value:parseInt(data.results.bindings[i].c.value)});
	      links.push({source:eNodes[endpoint], target:ot, id:d.id, type:"endpoint"});
	     }
	     
	     
	     if(p.length==0) {
			 var namespace = data.results.bindings[i].p.value.replace(/[^#|^/]+$/g,"");
			 var p = {namespace: namespace, source: d, target: ot, data: new Array({label:endpoint}), id: data.results.bindings[i].p.value, name:sparql.prefixify(data.results.bindings[i].p.value,sparql.lookup),type:"property"};	     
			ot.ref = p;
			links.push(p);
		 } else {
		  p = p[0];
		  p.data.push({label:endpoint});
		 }
	     

        } } }
        start();
	   });

start();
});
}

function getStatistics(arr,stats) {

for(i in arr) {

 if(arr[i].namespace!=undefined) {
	 
	namespace = arr[i].namespace; 
		
	for(d in arr[i].data) {	
		if(stats[namespace]==undefined) {
			stats[namespace]={namespace:namespace,usage:1,entities:[arr[i].name]}
		} else { 
	    stats[namespace].usage+=1; 
		stats[namespace].entities.push(arr[i].name); }
		}		
   }
}

}

function randXY(x,y,val) {
	if(val==undefined) val = 50;
 var rand = Math.random();
    var ag = rand * Math.PI * 2;
    var xl = x + Math.cos(ag) *val;
    var yl = y + Math.sin(ag) *val;  
    return {x:xl,y:yl};    
}



function start() {

// Created groups from the nodes	
group = [];

for(e in endpoints) {
var eh = $.grep(nodes, function(da){ 
	if(da.data!=undefined) return da.data.some(function(d){return (d.label==endpoints[e])}) 
	else return da.id==endpoints[e] 
	});
if(eh.length>2) group.push(eh);
}


// Calculating node sizes
for(i in nodes) {
	if(nodes[i].size==0) {
	for(d in nodes[i].data) {
		nodes[i].size+=parseInt(nodes[i].data[d].value);
	}
	nodes[i].size=Math.max(Math.log(nodes[i].size/((height/width)))*5,35)
	// Sorting data values
	if(nodes[i].data.length>1) {
		nodes[i].data.sort(function(a,b){return a.value - b.value; });
	}
	}
}

      force
      .nodes(nodes)
      .links(links)
      .start();
      
    var r = 35;  // radius
    var arc = d3.svg.arc().outerRadius(r);
   
  // FIXME: Remove this, and fix the bug? 
  color = ["#1f77b4", "#aec7e8",
  "#ff7f0e", "#ffbb78",
  "#2ca02c", "#98df8a",
  "#d62728", "#ff9896",
  "#9467bd", "#c5b0d5",
  "#8c564b", "#c49c94",
  "#e377c2", "#f7b6d2",
  "#7f7f7f", "#c7c7c7",
  "#bcbd22", "#dbdb8d",
  "#17becf", "#9edae5"];
  
  /* Links */
  
    link = svg.selectAll("line").data(force.links(), function(d) { return d.source.id + "-" + d.target.id; });
              
    link.enter().insert("line",".node")
        .attr("class", function(d) { if(d.type=="endpoint") { return "elink" } else { return "link" }} )
	  	.style("stroke", function(d) {  if(d.type=="endpoint" || d.data.length>1) { return "green"; } else { return color[endpoints.indexOf(d.data[0].label)]; } })

    link.exit().transition().duration(300).style("opacity", 0).remove(); 
  
  /* Links with names */
  
	var filth = links.filter(function(d) { return d.name != undefined; });

	path = svg.selectAll(".label").data(filth);
	
	path.enter().insert("text",".node")
	    .attr("class","label")
	    .style("fill", function(d) { if(d.data.length>1) { return "green"; } else { return color[endpoints.indexOf(d.data[0].label)]; } })
	    .text(function(d) { return d.name; });

	    
	//FIXME: This is not working?
	
	/*    
	    .on("mouseover",function(d) {
			console.log(d);
			var htmlString = "<h2>"+d.name+"</h2>";
			if(d.namespace!=undefined) {
				htmlString+="<p><b>Namespace: </b><a target='_blank' href='"+d.namespace+"'>"+d.namespace+"</a></p>";
			  }
			  htmlString+="<p><b>Source: </b>"+d.source.name+"</p>"
			  htmlString+="<p><b>Target: </b>"+d.target.name+"</p>"
			$("#details").html(htmlString);
		});
	*/
	
	path.exit().transition().duration(300).style("opacity", 0).remove();

        
  /* Nodes */
    
  node = svg.selectAll("g .node").data(force.nodes(), function(d) { return d.id;});
    
  g = node.enter().append("g")
      .attr("class", "node")
      .call(force.drag)
      .on("click",function(d) {
		  if(d.type=="endpoint") d.fixed = true;
	  })
      .on("mouseover",function(d) {
		  
		  var htmlString = "<h2 style='color:"+color[endpoints.indexOf(d.id)]+";'>"+d.name+"</h2>";
		  
		  if(loading) htmlString+="<p><h2>Loading ...</h2></p>";
		  if(d.type!="endpoint" && !loading) {
			  if(d.namespace!=undefined) {
				htmlString+="<p><b>Namespace: </b><a target='_blank' href='"+d.namespace+"'>"+d.namespace+"</a></p>";
			  }
			  if(d.type=="class") {
				 // htmlString+="<p><b>URI:</b> "+sparql.unprefixify(d.id)+"</p>";
			  if(propertyMode) {
			   var sameProperties = $.grep(links,function(e) { return e.source.id == d.id && e.target.data.length>1 });
			   var allProperties = $.grep(links,function(e) { return e.source.id == d.id });
			   if(!loading && sameProperties.length==0) htmlString+="<p><b style='color:red;'>No shared properties!</b></p>";
			   else {
				   htmlString+="<p><b>"+sameProperties.length+" shared properties</b></p>";
				   htmlString+="<p>"+((sameProperties.length/allProperties.length)*100).toFixed(1)+"% of all properties</p>";
			   }
			  } 
		  }
			  if(d.type=="classUsage" || d.type == "literalUsage") {
				  htmlString+="<p>Property: <b>"+d.ref.name+"</b></p>";
				  htmlString+="<p>Referenced by: "+d.ref.source.name+"</p>";
			  }
			  for(i in d.data) {
				  htmlString+="<div style='border-color:"+color[endpoints.indexOf(d.data[i].label)]+";' class='edetails'>";
				  htmlString+="<b style='color:"+color[endpoints.indexOf(d.data[i].label)]+"'>"+d.data[i].label+"</b>";
				  htmlString+="<p>"+d.data[i].value+" instances</p>"
				  if(d.type=="classUsage" || d.type == "literalUsage") {
				  var sourcedata = $.grep(d.ref.source.data, function(e){ return e.label == d.data[i].label});
				  htmlString+="<p>Coverage: "+((parseInt(d.data[i].value)/parseInt(sourcedata[0].value))*100).toFixed(1)+"%</p>"; }
				  htmlString+="</div>";
			  }
			  // Other nodes in this namespace
			  if(d.namespace!=undefined && d.type=="class") { 
				var arr = $.grep(nodes,function(e) { return e.namespace == d.namespace && e.id!=d.id }); 
				if(arr.length>0) {
					htmlString+="<div><h2>Resources in same namespace</h2><ul class='namespaces'>"
					for(i in arr) htmlString+="<li>"+arr[i].name+"</li>"
					htmlString+="</ul></div>";
					}
				  }
			  
	  }
		  $("#details").html(htmlString);
		  
	  })
       .on("contextmenu", function(d) {
          var htmlString = "<h4>"+d.name+"</h4>";
		  var t = d3.select("#tooltip")
		  .style("visibility", "visible")
		  .on("mouseover",function(d) { return d3.select("#tooltip").style("visibility", "visible"); })
		  .on("mouseout",function(d) { return d3.select("#tooltip").style("visibility", "hidden"); })
		  .style("top", (posY-20)+"px")
		  .style("left",(posX-20)+"px");

		  t.html(htmlString);
	
          d.fixed=false;
          
		 if(propertyMode) {
			 
			 	  t.append("a").attr("class", "button").on("click",function() {
				  d3.select("#tooltip").style("visibility", "hidden");
				  
				  d.objectProperties = false;
				  propertyMode=false;
				  hideOtherByType("class",true);
				  showSameClasses();
				  
				  start();
				  })
				  .text("Back to class usage"); 

		 }
		  
		  				
		  /* CLASS MENUS */
		  if(d.type=="class") {
			  /* SHOW properties*/
			  if(d.type=="class" & d.objectProperties==undefined || !d.objectProperties) {
				  
				  t.append("a").attr("class", "button").on("click",function() {
				  d3.select("#tooltip").style("visibility", "hidden");
				  
				  hideOther(d,false);
				  
				  if(d.objectProperties==undefined) { getPropertyUsages(d); }
				  else {
					   
					for(i=0;i<hLinks.length;i++) {
						// If links source is this node
						if(hLinks[i].source == d && hLinks[i].type == "property") {
							console.log("source is "+d.id);
							nodes.push(hLinks[i].target);
							links.push(hLinks[i]); 
							removeFromArray(hNodes,hLinks[i].target.id);
							hLinks.splice(i,1);
							i--;
					} else if(hLinks[i].id == d.id && hLinks.target!=d) {
						// Else if linkid is the same as the this nodes id
						links.push(hLinks[i]); 
						hLinks.splice(i,1);
						i--;
					}
					
					
					}
					
					  start();
					  }
				  
				   d.objectProperties = true;
				   propertyMode=true;
					
				  })
				  .text("Show property usage"); 
				  
			  } else { /* HIDE objectProperties */
				console.log(d);
			  }
   
   if(!propertyMode) {

			 /* HIDE CLASS */
			t.append("a").attr("class", "button").on("click",function() {
			  
			for(i=0;i<links.length;i++) {
				if(links[i].target == d || links[i].source == d) {
					//if(links[i].type != "refObject") 
					hLinks.push(links[i]);
					links.splice(i,1);
					i--;
				}}  
			  
			for(i=0;i<nodes.length;i++) {
				if(nodes[i] == d) {
					hNodes.push(nodes[i]);
					nodes.splice(i,1);
					i--;
				}}

			d3.select("#tooltip").style("visibility", "hidden");
			start();	  	  
			}).text("Hide");
		
}
  }
  
 t.append("a").attr("class","button").on("click",function() { d.fixed=true; d3.select("#tooltip").style("visibility", "hidden");}).text("Fixed position");
		  
    d3.event.preventDefault();
})
      .each(function(d) {

		 if(d.data!=undefined && d.type=="literalUsage") {
			  
			  var total=0;
			  var litWidth=80;
			  var litHeight=25;
			  var litX=-40;
			  
			  console.log(d);
			  for(i in d.data) total+=d.data[i].value; 
			  
			  console.log(total);
			  
			  var lit = d3.select(this).selectAll("g.lit").data(d.data).enter().append("rect").attr("class", "lit").style("top", "0px")
		  .style("left","0px");
  
			  lit.attr("width",function(d){return litWidth*(d.value/total)})
			  .attr("x",function(d){
				  console.log(litX);
				  var retX = litX;
				  litX+=litWidth*(d.value/total); 
				  return retX;
				  })
			   .attr("y",-10)
			  .attr("fill", function(d) { return  color[endpoints.indexOf(d.label)] })
			  .attr("height",litHeight);
			  
			  		  
			  
		  }
		 else if(d.data!=undefined && d.data[0].value!=undefined) { 
			 
		
	    arc.outerRadius(d.size)

		 var arcs = d3.select(this).selectAll("g.slice")    
        .data(d3.layout.pie().value(function(d) { return d.value; })(d.data))                        
        .enter()                          
        .append("g")          
        .attr("class", "slice");
        
        if(d.type=="literalUsage") { arc.outerRadius(r-5); arcs.attr("stroke","gray").attr("stroke-width","2px")}
        
		arcs.append("svg:path")
        .attr("fill", function(d) { return  color[endpoints.indexOf(d.data.label)] })
        .attr("d", arc);
        
	} else {
	
	/* Endpoint nodes */
	
	var circle = d3.select(this).append("use")
	.attr('xlink:href', '#db')
    .attr("fill", function(d) {  return  color[endpoints.indexOf(d.id)] })
    .attr("transform","scale(0.5)")
    .attr("x",-80)
    .attr("y",-110)
    .attr("class", function(d) { return d.type; });
    //.attr("style","opacity:0.5;"); 
    d3.select(this)
      .on("contextmenu", function(d) {
	     var htmlString = "<h4>"+d.name+"</h4>";
		  var t = d3.select("#tooltip")
		  .style("visibility", "visible")
		  .on("mouseover",function(d) { return d3.select("#tooltip").style("visibility", "visible"); })
		  .on("mouseout",function(d) { return d3.select("#tooltip").style("visibility", "hidden"); })
		  .style("top", (posY-20)+"px")
		  .style("left",(posX-20)+"px");
          t.html(htmlString);
          
          			  /* SHOW ALL CLASSES */
	         t.append("a").attr("class","button").on("click",function() {
				  // Loop all hidden nodes
				  for(i=0;i<hNodes.length;i++) {
					// Loop all endpoints
					for(f in hNodes[i].data) {
						// If there is node with the same endpoint
						if(hNodes[i].type=="class" && hNodes[i].data[f].label == d.id) {
							var xyrand = randXY(d.x,d.y);
							hNodes[i].x = xyrand.x;
							hNodes[i].y = xyrand.y;
							nodes.push(hNodes[i]);
							// Loop trough all hidden links
							for(h=0;h<hLinks.length;h++) 
								if(hLinks[h].type=="endpoint" && hLinks[h].target == hNodes[i]){
									links.push(hLinks[h]);
									hLinks.splice(h,1);
									h--;
								}
							 // Remove from hidden nodes and end this loop	
							 hNodes.splice(i,1);	
							 i--;
							 break;
							}
						  }
						}	
				  start();
			  }).text("Show all classes");
			  /* HIDE ALL CLASSES */
			  //FIXME: Implement

		  
		  t.append("a").attr("class","button").on("click",function() { for(i in nodes) nodes[i].fixed=true; d3.select("#tooltip").style("visibility", "hidden");}).text("Fix all nodes");
	  d3.event.preventDefault();
	  })
    .on("mouseover",function(d){
		
		var htmlString = "<h2 style='color:"+color[endpoints.indexOf(d.id)]+";'>"+d.name+"</h2>";
		  
		  if(loading) htmlString+="<p><h2>Loading ...</h2></p>";
		  if(d.type=="endpoint" && !loading) {
			  htmlString+="<div style='border-color:"+color[endpoints.indexOf(d.id)]+";' class='edetails'>";
			  htmlString+="<p><b>Number of instances</b>: "+d.totalCount+"</p>";
			  htmlString+="<p>"+((d.totalCount/totalInstances)*100).toFixed(1)+"% of instances from all endpoints</p>";
			  htmlString+="<p><b>Number of same classes</b>: "+d.sameClass+"</p>";
			  htmlString+="<p>"+((d.sameClass/sameClasses)*100).toFixed(1)+"% of all of the same classes</p>";
			  htmlString+="<p><b>Instances with the same class</b>: "+d.sameCount+"</p>";
			  htmlString+="<p>"+((d.sameCount/d.totalCount)*100).toFixed(1)+"% of this endpoints instances</p>";
			  htmlString+="</div>";
		
		      htmlString+="<div ><h2>Used class vocabularies</h2><ul class='namespaces'>";
		      for(i in d.namespaces) htmlString+="<li><b>"+d.namespaces[i].usage+"</b> classes <a target='_blank' href='"+d.namespaces[i].namespace+"'>"+d.namespaces[i].namespace+"</a></li>";
		      htmlString+="</ul></div>";
			  
			  $("#details").html(htmlString); }
		
		 
		 d3.select("#group"+endpoints.indexOf(d.id)).style("opacity",0.8); 
		 
		  })
    .on("mouseout",function(d){ d3.select("#group"+endpoints.indexOf(d.id)).style("opacity",0.15); });
    
    
	}
		 
	  });

/* Node text */

      g.append("text")
        .attr("class", "tip")
        .attr("dx", 0)
        .text(function(d) { return d.name })
        .style("font-size", "40px") // initial guess
        .style("font-size", function(d) { if(d.type=="literalUsage") return 15; else return (4 * d.size) / this.getComputedTextLength() * 15 + "px"; })
        .attr("dy", ".35em")
        .attr("text-anchor", "middle");     

  node.exit().transition().duration(300).style("opacity", 0).remove();

/* Venn groups */

gr = svg.selectAll(".group")
    .data(group)
    .attr("d", groupPath);
    
    gr.enter().insert("path", ".node")
      .attr("id",function(d) { return "group"+endpoints.indexOf(d[0].id); })
      .attr("class","group")
      .style("stroke", function(d) { return color[endpoints.indexOf(d[0].id)]})
      .style("fill", function(d) { return color[endpoints.indexOf(d[0].id)]})
      .style("stroke-width", 120)
      .style("stroke-linejoin", "round");
      //.style("opacity", .15);

gr.exit().remove();


}

function showSameClasses() {
	// Show all hidden classes
	for(i=0;i<hNodes.length;i++) {
	if(hNodes[i].type=="class" && hNodes[i].data.length>1 || hNodes[i].data == undefined) {
		nodes.push(hNodes[i]);
		hNodes.splice(i,1);
		i--;
	}}
    //  Show all hidden class links
	for(h=0;h<hLinks.length;h++) {
		if(hLinks[h].type!="property" && hLinks[h].target.data.length>1) {
			links.push(hLinks[h]);
			hLinks.splice(h,1);
			h--;
	}}
	
}

function hideOther(d,hide) {
	for(i=0;i<links.length;i++) {
		hLinks.push(links[i]);
		links.splice(i,1);
		i--;
	}  
			  
	for(i=0;i<nodes.length;i++) {
		if(nodes[i].type!="endpoint" && nodes[i] != d) {
			hNodes.push(nodes[i]);
			nodes.splice(i,1);
			i--;
	}}
}

function hideOtherByType(type,hide) {
	for(i=0;i<links.length;i++) {
		hLinks.push(links[i]);
		links.splice(i,1);
		i--;
	}  
			  
	for(i=0;i<nodes.length;i++) {
		if(nodes[i].type!="endpoint" && (nodes[i].type != type || nodes[i].data.length<2)) {
		
			hNodes.push(nodes[i]);
			nodes.splice(i,1);
			i--;
	} else { nodes[i].objectProperties = false; }
	
	}
}

function removeFromArray(arr,id) {
	for(i=0;i<arr.length;i++) 
	  if(arr[i].id == id) {
		console.log("removed "+arr[i].id);
		arr.splice(i,1);
	    break; }
}

var groupPath = function(d) {
    return "M" + 
      d3.geom.hull(d.map(function(i) { return [i.x, i.y]; })).join("L")
    + "Z";
};

function tick() {

  node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 
  .each(collide(.5));
  //collide(0.5);

  link.attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; });


  gr.attr("d", groupPath);
    
 path.attr("transform", function(d) 
	{

		var dx = (d.target.x - d.source.x),
		dy = (d.target.y - d.source.y);
		
		var dr = Math.sqrt(dx * dx + dy * dy);
		var sinus = dy/dr;
		var cosinus = dx/dr;
		var l = d.name.length*6;
		var offset = (1 - (l / dr )) / 2 ;
		var x=(d.source.x + dx*offset);
		var y=(d.source.y + dy*offset);
		
		if(d.offset!=undefined) {x=x+(d.offset*12); y=y+(d.offset*12); }
		
	    return "translate(" + x + "," + y + ") matrix("+cosinus+", "+sinus+", "+-sinus+", "+cosinus+", 0 , 0)";
	});
	
	

}

// Resolves collisions between d and all other circles.
function collide(alpha) {
	var padding = 20;
  var quadtree = d3.geom.quadtree(nodes);
  return function(d) {
	
    var r = d.size + padding,
        nx1 = d.x - r,
        nx2 = d.x + r,
        ny1 = d.y - r,
        ny2 = d.y + r;
    quadtree.visit(function(quad, x1, y1, x2, y2) {
      
      if (quad.point && (quad.point !== d)) {
        var x = d.x - quad.point.x,
            y = d.y - quad.point.y,
            l = Math.sqrt(x * x + y * y),
            r = d.size + quad.point.size + padding;
        if (l < r) {
          l = (l - r) / l * alpha;
          d.x -= x *= l;
          d.y -= y *= l;
          quad.point.x += x;
          quad.point.y += y;
        }
      }
      return x1 > nx2
          || x2 < nx1
          || y1 > ny2
          || y2 < ny1;
    });
  };
}


$("#add").click(function() { 

	var e = $("<li contenteditable='true' class='endpoint'>http://</li>");

	var length = $("#endpoints li").map(function(){ return $(this).text(); }).get().length;

	if(length<sparqlEndpoints.length) 
	e = $("<li id="+sparqlEndpoints[length].replace(/[^\w\s]/gi, '')+" contenteditable='true' class='endpoint'>"+sparqlEndpoints[length]+"</li>");

	e.focusout(function() {
		if($(this).text().length<1) $(this).remove();
		else e.attr('id', this.innerHTML.replace(/[^\w\s]/gi, '')); 
	});
	
	$("#endpoints").append(e);
	if(length+1>1) $("#radios").show();
	
});


$("#add").click();
$("#add").click();
$("#add").click();

$("#remove").click(function() {
	var length = $("#endpoints li").map(function(){ return $(this).text(); }).get().length;
	if(length>2) $("#endpoints li:last").remove();
	else alert("You need at least 2 endpoints");
});

$('.endpoint').focusout(function(){
	if($(this).text().length<1) $(this).remove();
	else $(this).attr('id', this.innerHTML.replace(/[^\w\s]/gi, ''));
});

$("#ok").click(function(e) {
 endpoints = $("#endpoints li").map(function(){ return $(this).text(); }).get();
 if($.grep(endpoints, function(e) { return e.indexOf("dbpedia") !== -1}).length==0) {
     e.preventDefault();
     $('#ok').unbind("click");
	 $('#ok').attr('disabled', 'disabled').addClass('disabled');
	 startGraph(); 
 }
 else alert("There is 288487 reasons why dbpedia is not allowed. Try \"select count(distinct ?class) { ?s a ?class }\"");
});



}); 

</script>
  
<body>
	<div id="wrapper">
      <div id="title"><h3 id="load"></h3></div>
      <div id="svg" class="container"></div>
      <div id="details"><div id="es"><h1>Force-directed pies</h1><p style="margin-top: 20px;"><h2>What is this madness?</h2> This demo visualizes usage of linked data vocabularies in multiple datasets. You can add and remove endpoints from +/- and edit endpoints by clicking.</p><h5>Edit endpoints <a id="add">+</a> <a id="remove">-</a></h5><ul id="endpoints"></ul><a class="btn" id="ok">I'm ready for it!</a></div></div>
   </div>
</body>
</html>
